<script setup lang="ts">

import {onMounted, ref, nextTick} from "vue";
import {addContent, delContent, findContentPage} from "@/api/content.ts";
import {ElMessage, ElMessageBox} from "element-plus";
import {ElLoading} from 'element-plus'
import request from '@/utils/request';
import type {FormInstance, FormRules} from 'element-plus'

// 定义接口类型
interface sysContent {
  id?: number;
  title: string;
  content: string;
  status: number;
  imgPath: string;
  moviePath: string;
  createTime: string;
  updateTime: string;
}

// 表单校验规则
const rules = ref<FormRules>({
  title: [
    {required: true, message: '请输入文章标题', trigger: 'blur'},
    {min: 1, max: 100, message: '标题长度应在 1 到 100 个字符之间', trigger: 'blur'}
  ],
  content: [
    {required: true, message: '请输入文章内容', trigger: 'blur'}
  ],
  status: [
    {required: true, message: '请选择文章状态', trigger: 'change'}
  ]
})

const form = ref<sysContent>({
  id: undefined,
  title: '',
  content: '',
  status: 1,
  imgPath: '',
  moviePath: '',
  createTime: '',
  updateTime: ''
})

const formRef = ref<FormInstance>()

// 定义文章对象
const contentInfo = ref<sysContent[]>([])

const editorRef = ref<HTMLTextAreaElement | null>(null)
const editorInstance = ref<any>(null)

const dialogTitle = ref('添加文章')
const addContentFlag = ref(false)

// 初始化富文本编辑器
const initEditor = () => {
  if (typeof window.tinymce === 'undefined') {
    console.error('TinyMCE 加载失败')
    return
  }

  window.tinymce.init({
    selector: 'textarea',
    target: editorRef.value,
    plugins: 'advlist autolink lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table wordcount  ',
    toolbar: 'undo redo | blocks | ' +
        'bold italic backcolor | alignleft aligncenter ' +
        'alignright alignjustify | bullist numlist outdent indent | ' +
        'removeformat | image table link  ',
    width: '100%',
    height: 650,
    language: 'zh_CN',
    menubar: 'file edit view insert format tools table help',
    branding: false,
    promotion: false,
    base_url: '/tinymce',
    suffix: '.min',
    skin: 'oxide',
    skin_url: '/tinymce/skins/ui/oxide',
    content_css: '/tinymce/skins/content/default/content.css',
    icons: 'default',
    icons_url: '/tinymce/icons/default/icons.min.js',
    font_formats: '微软雅黑=Microsoft YaHei,sans-serif;' +
        '宋体=SimSun,serif;' +
        '黑体=SimHei,sans-serif;' +
        '仿宋=FangSong,serif;' +
        '楷体=KaiTi,serif;' +
        'Arial=arial,helvetica,sans-serif;' +
        'Times New Roman=times new roman,times,serif;',
    fontsize_formats: '12px 14px 16px 18px 24px 36px 48px',
    paste_data_images: true,
    convert_urls: false,
    relative_urls: false,
    remove_script_host: false,
    inline: false,
    z_index: 30000,
    image_title: true,
    image_description: false,
    image_dimensions: true,
    image_class_list: [
      {title: 'Responsive', value: 'img-fluid'}
    ],
    automatic_uploads: true,
    file_picker_types: 'image media file',
    images_upload_base_path: '/uploads',
    images_upload_credentials: true,
    // 文件上传处理器 - 仅用于非图片文件
    file_picker_callback: (callback: (url: string, meta?: {
      text?: string,
      title?: string
    }) => void, value: string, meta: { filetype: string }) => {
      // 只处理非图片类型
      if (meta.filetype === 'image') {
        return false; // 强制用图片专用上传
      }
      const input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.setAttribute('accept', meta.filetype === 'media' ? 'video/*,audio/*' : '*');
      input.click();
      input.onchange = () => {
        const files = input.files;
        if (!files || files.length === 0) return;
        const file = files[0];
        const formData = new FormData();
        formData.append('file', file);
        const token = localStorage.getItem('token');
        fetch('/api/content/uploadFile', {
          method: 'POST',
          body: formData,
          headers: token ? {'satoken': token} : {}
        })
            .then(response => response.json())
            .then(data => {
              if (data.code === 200 && data.data?.url) {
                callback('/api' + data.data.url, {
                  text: file.name,
                  title: file.name
                });
              } else if (data.code === 403) {
                throw new Error("您没有权限");
              } else {
                throw new Error(data.msg || '上传失败');
              }
            })
            .catch(error => {
              console.error('文件上传失败:', error);
              alert(`文件上传失败: ${error.message}`);
            });
      };
    },
    images_upload_handler: (blobInfo: any, progress: any) => new Promise((resolve, reject) => {
      const formData = new FormData();
      formData.append('file', blobInfo.blob(), blobInfo.filename());

      // 从 localStorage 获取 token
      const token = localStorage.getItem('token');

      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/api/content/uploadImg', true);

      // 设置请求头
      if (token) {
        xhr.setRequestHeader('satoken', token);
      }
      xhr.upload.onprogress = (e) => {
        progress(e.loaded / e.total * 100);
      };

      xhr.onload = () => {
        if (xhr.status < 200 || xhr.status >= 300) {
          reject('上传失败: ' + xhr.statusText);
          return;
        }

        try {
          const json = JSON.parse(xhr.responseText);
          console.log('上传响应:', json); // 调试信息

          if (json.code === 200 && json.data?.url) {
            // 确保返回完整的URL路径
            let imageUrl = json.data.url;

            // 如果URL不是以http开头，则添加域名
            if (!imageUrl.startsWith('http')) {
              // 由于前端通过代理访问后端，图片URL需要指向后端服务器
              imageUrl = '/api' + imageUrl;
            }
            resolve(imageUrl);
          } else if (json.code === 403) {
            reject("您没有权限");
          } else {
            reject(json.msg || '上传失败');
          }
        } catch (e) {
          reject('解析响应数据失败');
        }
      };
      xhr.onerror = () => {
        reject('上传失败');
      };

      xhr.send(formData);
    }),
    setup: (editor: any) => {
      editorInstance.value = editor;
      editor.on('init', () => {
        console.log('TinyMCE 编辑器初始化完成');
        if (form.value.content) {
          editor.setContent(form.value.content);
        }
      });

      editor.on('change', () => {
        form.value.content = editor.getContent();
        // 手动触发 content 字段的验证
        if (formRef.value) {
          formRef.value.validateField('content')
        }
      });

      // 添加图片上传成功的事件监听
      editor.on('ObjectSelected', (e: any) => {
        if (e.target.nodeName === 'IMG') {
          console.log('选中图片:', e.target.src);
        }
      });
    }
  });
}

const pageNum = ref(1);
const total = ref(0);
const pageSize = ref(10);
const title = ref('');
const findContentList = async () => {
  let res = await findContentPage({pageNum: pageNum.value, pageSize: pageSize.value, title: title.value});
  if (res.code === 200) {
    contentInfo.value = res.data.records
    total.value = res.data.total
  }
}

const handleSizeChange = (val: number) => {
  pageSize.value = val
  findContentList()
}
const handleCurrentChange = (val: number) => {
  pageNum.value = val
  findContentList()
}

// 重置表单
const resetForm = () => {
  form.value = {
    id: undefined,
    title: '',
    content: '',
    status: 1,
    imgPath: '',
    moviePath: '',
    createTime: '',
    updateTime: ''
  }
  if (formRef.value) {
    formRef.value.resetFields()
  }
  if (editorInstance.value) {
    editorInstance.value.setContent('')
  }
}

// 新增文章
const handleAdd = () => {
  dialogTitle.value = '添加文章'
  resetForm()
  addContentFlag.value = true
  nextTick(() => {
    if (typeof window.tinymce === 'undefined') {
      const script = document.createElement('script')
      script.src = '/tinymce/tinymce.min.js'
      script.onload = initEditor
      document.head.appendChild(script)
    } else {
      initEditor()
    }
  })
}

// 编辑文章
const handleEdit = (row: sysContent) => {
  dialogTitle.value = '编辑文章'
  form.value = {...row}
  addContentFlag.value = true
  nextTick(() => {
    if (typeof window.tinymce === 'undefined') {
      const script = document.createElement('script')
      script.src = '/tinymce/tinymce.min.js'
      script.onload = initEditor
      document.head.appendChild(script)
    } else {
      initEditor()
    }
  })
}

// 提交表单
const handleSubmit = async () => {
  if (!formRef.value) return

  await formRef.value.validate(async (valid, fields) => {
    if (valid) {
      try {
        const loading = ElLoading.service({
          lock: true,
          text: form.value.id ? '正在保存...' : '正在添加...',
          background: 'rgba(0, 0, 0, 0.7)',
        })

        const res = await addContent(form.value)
        if (res.code === 200) {
          await findContentList()
          ElMessage.success(form.value.id ? '编辑成功' : '添加成功')
          addContentFlag.value = false
        } else if (res.code === 403) {
          ElMessage.error('您没有权限，请联系管理员')
        } else {
          ElMessage.error(res.msg || '操作失败')
        }

        loading.close()
      } catch (error) {
        console.error('操作失败:', error)
        ElMessage.error('操作失败，请重试')
      }
    } else {
      console.log('表单验证失败:', fields)
    }
  })
}

// 导出Word
const handleExportWord = async (row: sysContent) => {
  if (!row.id) {
    ElMessage.error('文章ID不存在');
    return;
  }

  const loading = ElLoading.service({
    lock: true,
    text: '导出中...',
    background: 'rgba(0, 0, 0, 0.7)',
  });

  try {
    // 使用request实例发送请求
    const response = await request({
      url: `/api/content/exportWord`,
      method: 'GET',
      params: {id: row.id},
      responseType: 'blob'
    });

    // 创建Blob对象
    const blob = new Blob([response.data], {
      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    });
    // 创建下载链接
    const downloadLink = document.createElement('a');
    downloadLink.href = URL.createObjectURL(blob);
    downloadLink.download = `${row.title || 'article'}.docx`;
    // 触发下载
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
    // 释放URL对象
    URL.revokeObjectURL(downloadLink.href);
    ElMessage.success('导出成功');
  } catch (error) {
    console.error('导出失败:', error);
    ElMessage.error('导出失败，请重试');
  } finally {
    loading.close();
  }
}

// 删除文章
const handleDelete = async (row: sysContent) => {
  try {
    await ElMessageBox.confirm('确认删除该文章吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    });
    let res = await delContent(row.id as number)
    if (res.code === 200) {
      await findContentList()
      ElMessage.success('删除成功');
    } else if (res.code === 403) {
      ElMessage.error('您没有权限，请联系管理员添加')
    }
  } catch {
    // 用户取消删除
  }
}

// 添加查看文章的数据
const viewDialogVisible = ref(false)
const currentArticle = ref<sysContent>({
  title: '',
  content: '',
  status: 1,
  imgPath: '',
  moviePath: '',
  createTime: '',
  updateTime: ''
})

// 查看文章
const handlePermission = (row: sysContent) => {
  currentArticle.value = {...row}
  viewDialogVisible.value = true
}

const search = async () => {
  await findContentList();
}

// 关闭对话框时清理编辑器
const handleDialogClose = () => {
  if (editorInstance.value) {
    window.tinymce.remove(editorInstance.value);
    editorInstance.value = null;
  }
  resetForm()
}

onMounted(() => {
  // 动态加载本地 TinyMCE 脚本
  const script = document.createElement('script');
  script.src = '/tinymce/tinymce.min.js';
  script.onload = () => {
    nextTick(() => {
      initEditor();
    });
  };
  document.head.appendChild(script);
  findContentList();
})

</script>

<template>
  <div>

    <el-card>
      <template #header>
        <div class="card-header">
          <span>文章列表</span>
          <el-button type="primary" @click="handleAdd">新增文章</el-button>
        </div>
      </template>
      <el-input v-model="title" placeholder="请输入标题" style="width: 200px; margin-bottom: 10px; margin-right: 10px"/>
      <el-button type="danger" style="margin-bottom: 10px;" @click="search">搜索</el-button>

      <el-table :data="contentInfo" border style="width: 100%">
        <el-table-column type="index" label="序号" width="80" align="center"></el-table-column>
        <el-table-column prop="title" label="文章标题" align="center"/>
        <el-table-column prop="createTime" label="创建时间" align="center">
          <template #default="{row}">
            {{ row.createTime ? row.createTime.replace('T', ' ') : '' }}
          </template>
        </el-table-column>
        <el-table-column prop="updateTime" label="修改时间" align="center">
          <template #default="{row}">
            {{ row.updateTime ? row.updateTime.replace('T', ' ') : '' }}
          </template>
        </el-table-column>
        <el-table-column label="操作" width="250" align="center">
          <template #default="{ row }">
            <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
            <el-button type="primary" link @click="handleDelete(row)">删除</el-button>
            <el-button type="primary" link @click="handlePermission(row)">查看</el-button>
            <el-button v-if="row.content" type="primary" link @click="handleExportWord(row)">导出word</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          v-model:current-page="pageNum"
          v-model:page-size="pageSize"
          :page-sizes="[10, 20, 50, 100]"
          :small="false"
          :disabled="false"
          :background="true"
          layout="total, sizes, prev, pager, next, jumper"
          :total="total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
      />
    </el-card>

    <!-- 添加/编辑文章对话框 -->
    <el-dialog
        style="margin-top: 0"
        v-model="addContentFlag"
        :title="dialogTitle"
        width="80%"
        :destroy-on-close="true"
        @close="handleDialogClose"
        append-to-body
        :modal-append-to-body="false"
        :close-on-click-modal="false"
    >
      <el-form
          ref="formRef"
          :model="form"
          :rules="rules"
          label-width="100px"
          status-icon
      >
        <el-form-item label="标题" prop="title">
          <el-input v-model="form.title" placeholder="请输入标题" style="width: 80%"/>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-radio-group v-model="form.status">
            <el-radio :value="1">启用</el-radio>
            <el-radio :value="0">禁用</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="文章内容" prop="content">
          <div class="editor-container">
            <textarea ref="editorRef"></textarea>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="addContentFlag = false">取消</el-button>
          <el-button type="primary" @click="handleSubmit">确定</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 查看文章对话框 -->
    <el-dialog
        v-model="viewDialogVisible"
        :title="currentArticle.title"
        width="80%"
        append-to-body
        :close-on-click-modal="false"
        destroy-on-close
    >
      <div class="article-content">
        <!-- 使用 v-html 渲染富文本内容 -->
        <div v-html="currentArticle.content"></div>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="viewDialogVisible = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<style>
/* 注意：这里不使用 scoped，确保样式能够影响到 TinyMCE 的弹出层 */
.tox-tinymce-aux {
  z-index: 31000 !important;
}

.tox-dialog {
  z-index: 31000 !important;
}

.tox-dialog__backdrop {
  z-index: 31000 !important;
}

.tox-menu {
  z-index: 31000 !important;
}

.tox-collection__group {
  z-index: 31000 !important;
}

.tox-statusbar__resize-handle {
  z-index: 31000 !important;
}

/* 文章内容样式 */
.article-content {
  padding: 20px;
  line-height: 1.6;
  font-size: 14px;
}

.article-content img {
  max-width: 100%;
  height: auto;
}

.article-content table {
  border-collapse: collapse;
  width: 100%;
  margin: 10px 0;
}

.article-content table td,
.article-content table th {
  border: 1px solid #dcdfe6;
  padding: 8px;
}

.article-content p {
  margin: 10px 0;
}

.article-content h1,
.article-content h2,
.article-content h3,
.article-content h4,
.article-content h5,
.article-content h6 {
  margin: 16px 0;
  font-weight: 600;
}

/* 添加必填项样式 */
.el-form-item.is-required .el-form-item__label::before {
  content: '*';
  color: #f56c6c;
  margin-right: 4px;
}

/* 调整表单验证样式 */
.el-form-item__error {
  padding-top: 4px;
  font-size: 12px;
}

.editor-container .el-form-item__error {
  position: absolute;
  top: 100%;
  left: 0;
}
</style>

<style scoped>
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}

.editor-container {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  width: 100%;
  min-height: 650px;
}

:deep(.tox-tinymce) {
  border: none !important;
}

:deep(.el-dialog) {
  display: flex;
  flex-direction: column;
  margin: 0 !important;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-height: 90%;
  max-width: 90%;
}

:deep(.el-dialog__body) {
  flex: 1;
  overflow: auto;
}

.el-pagination {
  margin-top: 20px;
  justify-content: flex-end;
}
</style>
